/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.uml_generator.manager.impl;

import com.genia.toolbox.basics.exception.BundledException;
import com.genia.toolbox.uml_generator.bean.ModelGeneratorContext;
import com.genia.toolbox.uml_generator.manager.ModelEnhancer;
import com.genia.toolbox.uml_generator.model.AbstractClassModel;
import com.genia.toolbox.uml_generator.model.AbstractDelegatableObject;
import com.genia.toolbox.uml_generator.model.AbstractJavaObject;
import com.genia.toolbox.uml_generator.model.AssociationCardinality;
import com.genia.toolbox.uml_generator.model.AssociationModel;
import com.genia.toolbox.uml_generator.model.AttributeModel;
import com.genia.toolbox.uml_generator.model.DataTypeModel;
import com.genia.toolbox.uml_generator.model.EnumerationModel;
import com.genia.toolbox.uml_generator.model.impl.AssociationEnd;
import com.genia.toolbox.uml_generator.model.impl.AssociationModelImpl;
import com.genia.toolbox.uml_generator.model.impl.AttributeModelImpl;
import com.genia.toolbox.uml_generator.model.impl.ClassModel;
import com.genia.toolbox.uml_generator.model.impl.InterfaceModel;
import com.genia.toolbox.uml_generator.visitor.ModelVisitor;

/**
 * implementation of {@link ModelEnhancer}.
 */
public abstract class AbstractModelEnhancerImpl
    implements ModelEnhancer
{

  /**
   * return a {@link ModelVisitor} used to enhance the model.
   * 
   * @return a {@link ModelVisitor} used to enhance the model
   */
  public abstract ModelVisitor createEnhancerVisitor();



  /**
   * allow to enhance the model with the needed informations for the generation.
   * 
   * @param context
   *          the context containing the model
   * @throws BundledException
   *           when an error occurred
   * @see com.genia.toolbox.uml_generator.manager.ModelEnhancer#enhanceModel(com.genia.toolbox.uml_generator.bean.ModelGeneratorContext)
   */
  public void enhanceModel(ModelGeneratorContext context)
      throws BundledException
  {
    for (AbstractClassModel classModel : context.getClasses().values()) {
      addObjectForQualifier(classModel);
    }
    ModelVisitor visitor = createEnhancerVisitor();
    for (AbstractClassModel classModel : context.getClasses().values()) {
      classModel.visit(visitor);
    }
    for (AbstractDelegatableObject classModel : context.getEnumerations().values()) {
      classModel.visit(visitor);
    }
  }



  /**
   * Add the attribute or association needed to handle the qualifiers.
   * 
   * @param classModel
   *          the class to inspect.
   * @throws BundledException
   *           when an error occurred
   */
  private void addObjectForQualifier(final AbstractClassModel classModel)
      throws BundledException
  {
    for (final AssociationModel association : classModel.getAssociations()) {
      if (association.getQualifier() != null) {
        association.getQualifier().getType().visit(new ModelVisitor()
        {

          public void visitSimpleType(AbstractJavaObject qualifierType)
          {
            AttributeModel qualifierAttribute = new AttributeModelImpl();
            qualifierAttribute.setComment(association.getQualifier().getComment());
            qualifierAttribute.setMappable(true);
            qualifierAttribute.setName(association.getQualifier().getName());
            qualifierAttribute.setType(association.getQualifier().getType());
            qualifierAttribute.setUmlId(association.getUmlId() + "Qualifier");
            association.getAssociatedType().addAttribute(qualifierAttribute);
          }



          public void visitComplexType(AbstractClassModel qualifierType)
          {
            AssociationModel qualifierAssociation = new AssociationModelImpl();
            qualifierAssociation.setOtherEnd(null);
            AssociationEnd currentEnd = new AssociationEnd();
            currentEnd.setType(association.getAssociatedType());
            currentEnd.setCardinality(AssociationCardinality.MANY);
            AssociationEnd otherEnd = new AssociationEnd();
            otherEnd.setComment(association.getQualifier().getComment());
            otherEnd.setName(association.getQualifier().getName());
            otherEnd.setUmlId(association.getUmlId() + "Qualifier");
            otherEnd.setType(qualifierType);
            otherEnd.setCardinality(AssociationCardinality.ONE);
            qualifierAssociation.setCurrentEnd(currentEnd);
            qualifierAssociation.setOtherEnd(otherEnd);

            association.getAssociatedType().addAssociation(qualifierAssociation);
          }



          public void visitClassModel(ClassModel classModel)
          {
            visitComplexType(classModel);
          }



          public void visitDataTypeModel(DataTypeModel dataTypeModel)
          {
            visitSimpleType(dataTypeModel);
          }



          public void visitEnumerationModel(EnumerationModel enumerationModel)
          {
            visitSimpleType(enumerationModel);
          }



          public void visitInterfaceModel(InterfaceModel interfaceModel)
          {
            visitComplexType(interfaceModel);
          }

        });
      }
    }
  }
}
